home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr47 / sb16snd.zip / SBIO.C < prev    next >
C/C++ Source or Header  |  1995-02-18  |  10KB  |  339 lines

  1. /*           Copyright 1995 by Ethan Brodsky.  All rights reserved          */
  2.  
  3. /* ██ SBIO.C ██████████████████████████████████████████████████████████████ */
  4.  
  5. /* ██ Interface ███████████████████████████████████████████████████████████ */
  6.  
  7. #define TRUE  1
  8. #define FALSE 0
  9.  
  10.   typedef enum {input, output} mode;
  11.  
  12.  /* Interface procedures and functions */
  13.   int init_sb
  14.    (
  15.     int  baseio,
  16.     char irq,
  17.     char dma16,
  18.     mode io,
  19.     unsigned int rate
  20.    );
  21.   void shutdown_sb(void);
  22.  
  23.   void startio(unsigned long length);
  24.   void sethandler(void far *proc);
  25.  
  26.   void getbuffer(int far **bufptr, unsigned int length);
  27.   void freebuffer(int far **bufptr);
  28.  
  29.  /* Interface variables that can be changed in the background */
  30.   volatile long intcount;
  31.   volatile int  done;
  32.   volatile char curblock;
  33.   volatile long samplesremaining;
  34.  
  35. /* ███ Implementation █████████████████████████████████████████████████████ */
  36.  
  37.  
  38. #include <alloc.h>
  39. #include <conio.h>
  40. #include <dos.h>
  41. #include <mem.h>
  42. #include <stdlib.h>
  43.  
  44. #define lo(value) (unsigned char)((value) & 0x00FF)
  45. #define hi(value) (unsigned char)((value) >> 8)
  46.  
  47.   int  resetport;
  48.   int  readport;
  49.   int  writeport;
  50.   int  pollport;
  51.   int  poll16port;
  52.  
  53.   int  pic_rotateport;
  54.   int  pic_maskport;
  55.  
  56.   int  dma_maskport;
  57.   int  dma_clrptrport;
  58.   int  dma_modeport;
  59.   int  dma_baseaddrport;
  60.   int  dma_countport;
  61.   int  dma_pageport;
  62.  
  63.   char irq_startmask;
  64.   char irq_stopmask;
  65.   char irq_intvector;
  66.   char int_controller;
  67.  
  68.   char dma_startmask;
  69.   char dma_stopmask;
  70.   char dma_mode;
  71.  
  72.   void interrupt (*oldintvector)() = NULL;
  73.   int  handlerinstalled;
  74.  
  75.   void far *memarea = NULL; /* Twice the size of the output buffer */
  76.   int  memareasize;
  77.  
  78.   unsigned long buf_addr;    /* 16-bit addressing */
  79.   unsigned char buf_page;
  80.   unsigned int  buf_ofs;
  81.  
  82.   int buf_length;            /* In words */
  83.   int block_length;          /* In words */
  84.  
  85.   unsigned int samplingrate;
  86.  
  87.   mode iomode;
  88.   void far (*handler)(void) = NULL;
  89.  
  90. /* ══ Low level sound card I/O ════════════════════════════════════════════ */
  91.   void write_dsp(unsigned char value)
  92.     {
  93.       while (inp(writeport) & 0x80);   /* Wait for bit 7 to be cleared */
  94.       outp(writeport, value);
  95.     }
  96.  
  97.   unsigned char read_dsp(void)
  98.     {
  99.       unsigned int value;
  100.  
  101.       while (!(inp(pollport) & 0x80)); /* Wait for bit 7 to be set */
  102.       value = inp(readport);
  103.       return value;
  104.     }
  105.  
  106.    int reset_dsp(void)
  107.      {
  108.        int i;
  109.  
  110.        outp(resetport, 1);
  111.        outp(resetport, 0);
  112.        i = 100;
  113.  
  114.        while ((read_dsp() != 0xAA) && i--);
  115.        return i;
  116.      }
  117.  
  118. /* ══ Initialization and shutdown ═════════════════════════════════════════ */
  119.   void installhandler(void);   /* Prototypes for private functions */
  120.   void uninstallhandler(void);
  121.   void sb_exitproc(void);
  122.  
  123.   int  init_sb(int baseio, char irq, char dma16, mode io, unsigned int rate)
  124.     {
  125.      /* Sound card IO ports */
  126.       resetport  = baseio + 0x006;
  127.       readport   = baseio + 0x00A;
  128.       writeport  = baseio + 0x00C;
  129.       pollport   = baseio + 0x00E;
  130.       poll16port = baseio + 0x00F;
  131.  
  132.      /* Reset DSP */
  133.       if (!reset_dsp()) return FALSE;
  134.  
  135.      /* Compute interrupt ports and parameters */
  136.       if (irq < 8)
  137.         {
  138.           int_controller = 1;
  139.           pic_rotateport = 0x20;
  140.           pic_maskport   = 0x21;
  141.           irq_intvector  = 0x08 + irq;
  142.         }
  143.       else
  144.         {
  145.           int_controller = 2;
  146.           pic_rotateport = 0xA0;
  147.           pic_maskport   = 0x21;
  148.           irq_intvector  = 0x70 + irq-8;
  149.         }
  150.       irq_stopmask  = 1 << (irq % 8);
  151.       irq_startmask = ~irq_stopmask;
  152.  
  153.      /* Compute DMA ports and parameters */
  154.       dma_maskport     = 0xD4;
  155.       dma_clrptrport   = 0xD8;
  156.       dma_modeport     = 0xD6;
  157.       dma_baseaddrport = 0xC0 + 4*(dma16-4);
  158.       dma_countport    = 0xC2 + 4*(dma16-4);
  159.  
  160.       switch(dma16)
  161.         {
  162.           case 5:  dma_pageport = 0x8B; break;
  163.           case 6:  dma_pageport = 0x89; break;
  164.           case 7:  dma_pageport = 0x8A; break;
  165.         }
  166.  
  167.       dma_stopmask  = dma16-4 + 0x04;    /* 000001xx */
  168.       dma_startmask = dma16-4 + 0x00;    /* 000000xx */
  169.  
  170.      /* Other initialization */
  171.       samplingrate = rate;
  172.       iomode = io;
  173.       switch (iomode)
  174.         {
  175.           case input:  dma_mode = dma16-4 + 0x54; break;  /* 010101xx */
  176.           case output: dma_mode = dma16-4 + 0x58; break;  /* 010110xx */
  177.         }
  178.  
  179.       installhandler();    /* Install interrupt handler */
  180.       atexit(sb_exitproc); /* Install exit procedure    */
  181.  
  182.       return TRUE;
  183.     }
  184.  
  185. /* ──────────────────────────────────────────────────────────────────────── */
  186.  
  187.   void shutdown_sb(void)
  188.     {
  189.       if (handlerinstalled) uninstallhandler();
  190.       reset_dsp();
  191.     }
  192.  
  193. /* ════════════════════════════════════════════════════════════════════════ */
  194.  
  195.   void startio(unsigned long length)
  196.     {
  197.       done = FALSE;
  198.       samplesremaining = length;
  199.       curblock = 0;
  200.  
  201.       samplesremaining -= block_length;
  202.  
  203.      /* Program DMA controller */
  204.       outp(dma_maskport,     dma_stopmask);
  205.       outp(dma_clrptrport,   0x00);
  206.       outp(dma_modeport,     dma_mode);
  207.       outp(dma_baseaddrport, lo(buf_ofs));           /* Low byte of offset  */
  208.       outp(dma_baseaddrport, hi(buf_ofs));           /* High word of offset */
  209.       outp(dma_countport,    lo(buf_length-1));      /* Low byte of count   */
  210.       outp(dma_countport,    hi(buf_length-1));      /* High byte of count  */
  211.       outp(dma_pageport,     buf_page);
  212.       outp(dma_maskport,     dma_startmask);
  213.  
  214.      /* Program sound card */
  215.       switch (iomode)
  216.         {
  217.           case input:  write_dsp(0x42); break;  /* Set input sampling rate  */
  218.           case output: write_dsp(0x41); break;  /* Set output sampling rate */
  219.         }
  220.       write_dsp(hi(samplingrate));            /* High byte of sampling rate */
  221.       write_dsp(lo(samplingrate));            /* Low byte of sampling rate  */
  222.       switch (iomode)
  223.         {
  224.           case output: write_dsp(0xB6); break;  /* 16-bit D->A, A/I, FIFO   */
  225.           case input:  write_dsp(0xBE); break;  /* 16-bit A->D, A/I, FIFO   */
  226.         }
  227.       write_dsp(0x10);                     /* DMA Mode:  16-bit signed mono */
  228.       write_dsp(lo(block_length-1));       /* Low byte of block length      */
  229.       write_dsp(hi(block_length-1));       /* High byte of block length     */
  230.     }
  231.  
  232. /* ══ Interrupt handling ══════════════════════════════════════════════════ */
  233.  
  234.   void sethandler(void far *proc)
  235.     {
  236.       handler = proc;
  237.     }
  238.  
  239. /* ──────────────────────────────────────────────────────────────────────── */
  240.  
  241.   void interrupt inthandler()
  242.     {                               /* CurBlock -> Block that just finished */
  243.       intcount++;
  244.  
  245.       if (handler != NULL) (*handler)();
  246.  
  247.       samplesremaining -= block_length;
  248.       curblock = !curblock;         /* Toggle current block */
  249.       if (samplesremaining < 0)
  250.         {
  251.           done = TRUE;
  252.           write_dsp(0xD9);
  253.         }
  254.  
  255.       inp(poll16port);
  256.       outp(0x20, 0x20);
  257.       outp(0xA0, 0x20);
  258.     }                                /* CurBlock -> Block that just started */
  259.  
  260.  
  261. /* ──────────────────────────────────────────────────────────────────────── */
  262.  
  263.   void installhandler(void)
  264.     {
  265.       disable();                                     /* Disable interrupts  */
  266.       outp(pic_maskport, (inp(pic_maskport)|irq_stopmask));  /* Mask IRQ    */
  267.  
  268.       oldintvector = getvect(irq_intvector);         /* Save old vector     */
  269.       setvect(irq_intvector, inthandler);            /* Install new handler */
  270.  
  271.       outp(pic_maskport, (inp(pic_maskport)&irq_startmask)); /* Unmask IRQ  */
  272.       enable();                                      /* Reenable interupts  */
  273.  
  274.       handlerinstalled = TRUE;
  275.  
  276.     }
  277.  
  278. /* ──────────────────────────────────────────────────────────────────────── */
  279.  
  280.   void uninstallhandler(void)
  281.     {
  282.       disable();                                     /* Disable interrupts  */
  283.       outp(pic_maskport, (inp(pic_maskport)|irq_stopmask)); /* Mask IRQ     */
  284.  
  285.       setvect(irq_intvector, oldintvector);          /* Restore old vector  */
  286.  
  287.       enable();                                      /* Enable interrupts   */
  288.  
  289.       handlerinstalled = FALSE;
  290.     }
  291.  
  292. /* ══ Memory management ═══════════════════════════════════════════════════ */
  293.  
  294.   unsigned long getlinearaddr(int far *p)
  295.     {
  296.       unsigned long addr;
  297.  
  298.       addr = (unsigned long)FP_SEG(p)*16 + (unsigned long)FP_OFF(p);
  299.       return(addr);
  300.     }
  301.  
  302. /* ──────────────────────────────────────────────────────────────────────── */
  303.  
  304.   void getbuffer(int far **bufptr, unsigned int length)
  305.     {
  306.      /* Find a block of memory that does not cross a page boundary */
  307.       memareasize = 8 * length;
  308.       if ((memarea = malloc(memareasize)) == NULL) /* Can't allocate mem?   */
  309.         exit(EXIT_FAILURE);                        /*  error                */
  310.       *bufptr = (int far *)memarea;                /* Pick first half       */
  311.       if (((getlinearaddr(memarea) >> 1) % 65536) + length*2 > 65536)
  312.         *bufptr += 2*length; /* Pick second half to avoid crossing boundary */
  313.  
  314.      /* DMA parameters */
  315.       buf_addr = getlinearaddr(*bufptr);
  316.       buf_page = buf_addr >> 16;
  317.       buf_ofs  = (buf_addr >> 1) % 65536;
  318.       buf_length = length*2;  block_length = length;          /* In samples */
  319.     }
  320.  
  321. /* ──────────────────────────────────────────────────────────────────────── */
  322.  
  323.   void freebuffer(int far **bufptr)
  324.     {
  325.       *bufptr = NULL;
  326.       free((void *)memarea);
  327.     }
  328.  
  329. /* ══ Exit shutdown ═══════════════════════════════════════════════════════ */
  330.   void sb_exitproc(void)
  331.     {
  332.       outp(0x20, 0x20);  outp(0xA0, 0x20);  /* Acknowledge any hanging ints */
  333.       write_dsp(0xD5);                      /* Pause digitized sound output */
  334.       outp(dma_maskport, dma_stopmask);     /* Mask DMA channel             */
  335.       if (handlerinstalled) uninstallhandler(); /* Uninstall int handler    */
  336.       reset_dsp();                          /* Reset SB DSP                 */
  337.     }
  338.  
  339.